package cn.bonoon.kernel.web.handlers;

import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.List;

import cn.bonoon.kernel.IdGenerator;
import cn.bonoon.kernel.events.DialogEvent;
import cn.bonoon.kernel.util.StringHelper;
import cn.bonoon.kernel.web.ButtonEventType;
import cn.bonoon.kernel.web.ButtonRefreshType;
import cn.bonoon.kernel.web.KeyChecker;
import cn.bonoon.kernel.web.controllers.BaseButtonResolver;
import cn.bonoon.kernel.web.controllers.FormButtonResolver;
import cn.bonoon.kernel.web.models.StandardModel;
import cn.bonoon.kernel.web.models.DialogModel;

/**
 * <pre>
 * 设置弹出对话框的一些基本信息，包括对界面的自动解析等操作
 * 
 * 如果是非自动解析界面的，应该使用哪个处理器？？
 * 创建对象后需要先调用初始化函数{@link #register(BaseButtonResolver)}
 * 执行生成界面的则需要调用{@link #execute(DialogModel, DialogEvent)}
 * 
 * 直接使用{@link AbstractExecuteHandler#key}作为弹出对话框的ID值
 * </pre>
 * @author jackson
 * @see AbstractExecuteHandler
 */
public abstract class AbstractDialogHandler extends AbstractExecuteHandler{
	/**
	 * 如果宽度为0，则表示宽度自动适应
	 */
	protected int width, height, maxHeight;
	protected boolean closeButton;
	protected String title;
	protected String viewName;
	protected String dialogMaster;

	/**
	 * 这个刷新是针对弹出的对话框的，该属性告诉生成器，是否需要在当对话框被关闭的时候或其它定义的情况，调用父容器的刷新语句
	 */
	protected ButtonRefreshType refreshType = ButtonRefreshType.FINISH;
	private String onClosedEvent;
	private ArrayList<FormButtonResolver> buttons;
	private List<FormButtonResolver> toolbar;
	
	/**
	 * 该组件所在的父组件的注册处理器
	 */
	protected final HandlerRegister parentRegister;
	protected final StringBuilder block;
	protected final String closeDialog;
	protected boolean closable = true, modal = true;
	protected boolean maximizable = false;
	protected boolean maximized = false;
	
	public void addBlock(String block){
		this.block.append(block);
	}
	
	protected AbstractDialogHandler(AnnotatedElement ae, HandlerRegister parentRegister) throws Exception{
		super(ae, "do");
		this.block = new StringBuilder();
		this.parentRegister = parentRegister;
		
		this.closeDialog = "jQuery('#" + key + "').bupdlg('close');";
	}
	
	/**
	 * <pre>
	 * 向对话框添加操作按钮
	 * 添加操作按钮的操作必须在{@link #initRegister()}初始化之前被调用；
	 * 因为在初始化的时候就会对添加的按钮进行处理
	 * </pre>
	 * @param btn
	 */
	public void addButton(FormButtonResolver btn){
		if(null == buttons){
			buttons = new ArrayList<FormButtonResolver>(1);
		}
		buttons.add(btn);
	}
	
	/**
	 * 对话框所在的toolbar工具栏上
	 * @param btn
	 */
	public void addToolbar(FormButtonResolver btn){
		if(null == toolbar){//一般的情况下toolbar的按钮平均不会超过三个
			toolbar = new ArrayList<FormButtonResolver>(3);
		}
		toolbar.add(btn);
	}
	
	protected void parse(StringBuilder html, StringBuilder block, StringBuilder dlgAttrs){
		dlgAttrs.append(" title='").append(title).append('\'');

		StringBuilder buttonSource = new StringBuilder();
		if(null != buttons){
			_parse(/*"dlg-btn-", */buttons, buttonSource, block);
		}
		if(closeButton){
			buttonSource.append("<a href='#' onclick=\"").append(closeDialog).append("return false;\">关闭</a>");
		}
		if(buttonSource.length() > 0){
			//需要显示按钮
			String btnid = IdGenerator.fixed();
			dlgAttrs.append(" buttons='#").append(btnid).append("'");
			html.append("<div id='").append(btnid).append("' style='height:30px'>").append(buttonSource).append("</div>");
			block.append("jQuery('#").append(btnid).append(" a').bupabutton({flat:true});");
		}
		
		if(null != toolbar && !toolbar.isEmpty()){
			String tbid = IdGenerator.fixed();
			html.append("<div id='").append(tbid).append("'>");
			_parse(/*"dlg-tb-", */toolbar, html, block);
			html.append("</div>");
			
			dlgAttrs.append(" data-settings=\"toolbar:'#").append(tbid).append("'\"");
			block.append("jQuery('#").append(tbid).append(" a').bupabutton({flat:true});");
		}
	}
	
	protected void _parse(/*String pre, */List<FormButtonResolver> btns, StringBuilder html, StringBuilder block){
//		int index = 0;
//		String btn = pre + key + "-";
		for (FormButtonResolver button : btns) {
			//通过velocity来控制访问的权限
			int key = button.getKey();
			String buttonId = IdGenerator.fixed();//btn + index ++;
			if(key > 0){
				html.append(" #if(${").append(KeyChecker.CHECKER_PROPERTY_NAME).append(".check(").append(key).append(")})");
				_parse(buttonId, button, html, block);
				html.append("#end\n");
			}else{
				_parse(buttonId, button, html, block);
			}
		}
	}

	protected void _parse(String buttonId, FormButtonResolver button, StringBuilder html, StringBuilder block){
		if(button.clickable()){
			String funName = button.getFunctionName();
			block.append("jQuery('#").append(buttonId).append("').click(");
			if(StringHelper.isEmpty(funName)){
				//向控制器注册处理事件
				block.append("function(){");
				button.event(block, key);
				block.append("}");
			}else{
				block.append(funName);
			}
			block.append(");");
		}
		button.button(html, buttonId);
	}
	
	/**
	 * <pre>
	 * 是否显示对话框右下方的关闭按钮
	 * 
	 * 注意与{@link setClosable}的区别
	 * 两者可以分别设置
	 * 
	 * </pre>
	 * @param closeButton
	 */
	public void set(String title, boolean closeButton) {
		this.title = title;
		this.closeButton = closeButton;
	}
	
	public void size(int width, int height){
		this.width = width;
		this.height = height;
	}
	
	public void setMaxHeight(int height) {
		this.height = height;
	}
	
	/**
	 * <pre>
	 * 弹出对话框
	 * </pre>
	 * @param event
	 * @return
	 * @throws Exception
	 */
	public final StandardModel execute(DialogModel model, DialogEvent event) throws Exception {
		model.setWidth(width);
		model.setHeight(height);
		model.setMaxHeight(maxHeight);
		model.setMaster(dialogMaster);
		model.setClosable(closable);
		model.setMaximizable(maximizable);
		model.setMaximized(maximized);
		model.setModal(modal);
		
		model.addClosedEvent(onClosedEvent);
		
		internalExecute(model, event);
		return model.execute(viewName);
	}
	
	/**
	 * <pre>
	 * 每次弹出对话框时都会被调用的内部处理函数
	 * </pre>
	 * @param model
	 * @param event
	 * @throws Exception
	 */
	protected abstract void internalExecute(DialogModel model, DialogEvent event) throws Exception;

	/**
	 * <pre>
	 * 定义给外部调用的初始化函数；
	 * 初始化函数是初始化整个对话框的参数，只有在该处理器被创建的时候调用一次；
	 * 而函数{@link #execute(DialogEvent)}则是在每次打开对话框的时候被调用
	 * </pre>
	 * @throws Exception
	 */
	public BaseButtonResolver register(BaseButtonResolver resolver)throws Exception{
		parentRegister.getManager().register(this);
		resolver.setUrl(getUrl());
		resolver.setEventType(ButtonEventType.DIALOG);
		resolver.setRefreshType(refreshType);
		if(refreshType == ButtonRefreshType.ONCLOSE){
			onClosedEvent = parentRegister.refreshParentComponenet();
		}
		return resolver;
	}

	public ButtonRefreshType getRefreshType() {
		return refreshType;
	}

	public void setRefreshType(ButtonRefreshType refreshType) {
		this.refreshType = refreshType;
	}
}
